package cn.itsource.hrm.task;

import cn.itsource.hrm.Thread.AddUserRunnable;
import cn.itsource.hrm.service.IUserService;
import cn.itsource.hrm.utils.MyTools;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

//读取Excel入库操作-采用线程池
@Component
public class ReadExcelThreadPoolTask {

    @Autowired
    private IUserService userService;

    /**
     * IO密集型任务 = 一般为2*CPU核心数（常出现于线程中：数据库数据交互、文件上传下载、网络数据传输等等）
     * CPU密集型任务 = 一般为CPU核心数+1（常出现于线程中：复杂算法）
     * 混合型任务 = 根据机器配置和复杂度自测而定
     */
    private static int corePoolSize = Runtime.getRuntime().availableProcessors();//返回JVM虚拟机可用核心数

    //自定义线程池
    private static ThreadPoolExecutor executor = new ThreadPoolExecutor(
            corePoolSize, //指定核心线程数量
            2*corePoolSize, //指定最大线程数
            60L, //指定线程空闲后的最大存活时间
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<Runnable>(), //任务较多时暂存到此队列（无界队列）
            //当线程大于总数(最大线程数 + 阻塞队列)时，将由下面的handler参数拒绝任务
            /**
             * 1、AbortPolicy：这个拒绝策略就是Java提供的四种线程池创建方法提供的默认拒绝策略，直接抛RejectedExecutionException异常
             * 2、CallerRunsPolicy：此拒绝策略简单来说就是将此任务交给调用者直接执行
             * 3、DiscardOldestPolicy：此拒绝策略是丢弃队列中最老的任务，然后再执行
             * 4、DiscardPolicy：此拒绝策略简单来说就是直接丢弃了当前任务不执行
             */
            new ThreadPoolExecutor.DiscardPolicy() //策略：丢弃任务
    );

    //每X秒运行一次
    @Scheduled(cron = "0/30 * * * * *")
    public void readExcelTask() throws InterruptedException {
        System.out.println("线程池 开始执行任务了，corePoolSize=" + corePoolSize);
        //获取所有文件
        List<String> excelPathList = MyTools.getFolderFile("E:\\excel");

        CountDownLatch cdl = new CountDownLatch(excelPathList.size());//50
        //cdl.await();
        //cdl.countDown();
        if(excelPathList != null && excelPathList.size() > 0){
            long t1 = System.currentTimeMillis();
            //TODO 主业务逻辑
            for (String excelPath : excelPathList) {
                //调用execute方法执行任务
                executor.execute(new AddUserRunnable(excelPath, userService, cdl));
            }
            cdl.await();
            long t2 = System.currentTimeMillis();
            //TODO 如何计算耗时才合理？
            System.out.println("耗时：" + (t2-t1) + "毫秒");//这样计算耗时有问题
        }
    }
}